#pragma once
#include <iostream>
#include <string>

#include <cstring>
#include <cerrno>

#include <sys/epoll.h>

#include "Log.hpp"
#include "Err.hpp"

const static int defaultepfd = -1;
const static int epfdsize = 128;

// 封装epoll的方法
class Epoller
{
public:
    Epoller() : _epfd(-1) {}
    ~Epoller()
    {
        if (_epfd != defaultepfd)
            close(_epfd);
    }

public:
    void Create()
    {
        _epfd = epoll_create(epfdsize);
        if (_epfd == defaultepfd)
        {
            LogMessage(FATAL, "epoll creat epfd error! code:%d errstring:%s", errno, strerror(errno));
            exit(EPOLL_ERR);
        }
    }

    // user -> kernel
    bool AddEvent(int sockfd, uint32_t event)
    {
        struct epoll_event ev;
        ev.events = event;
        ev.data.fd = sockfd;

        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, sockfd, &ev);
        return n == 0;
    }

    // 返回就绪事件的数量  kernel -> user
    int Wait(struct epoll_event revs[], int num, int timeout)
    {
        int n = epoll_wait(_epfd, revs, num, timeout);
        return n;
    }

    // 用于控制/更新epooler中已经关心的fd的就绪事件状态
    bool Control(int sockfd, uint32_t event, int action)
    {
        int n = -1;
        if (action == EPOLL_CTL_MOD)
        {
            struct epoll_event ev;
            ev.data.fd = sockfd;
            ev.events = event;

            n = epoll_ctl(_epfd, action, sockfd, &ev);
        }
        else if (action == EPOLL_CTL_DEL)
        {
            n = epoll_ctl(_epfd, action, sockfd, nullptr);
        }
        else
            n = -1;
        return n == 0;
    }

private:
    int _epfd; // epoll模型的文件描述符
};

// 封装返回的就绪事件
class Revent
{
public:
    int _sock;
    uint32_t _revent;
};